﻿using Futuret.Core.DependencyInjection.Attribute;
using Futuret.Core.DependencyInjection.Dependencies;
using Futuret.Core.Extensions;
using Futuret.Core.Futuret;
using Futuret.Core.Futuret.Interface;
using Microsoft.Extensions.Hosting;

namespace Futuret.Core.DependencyInjection.Extensions;

/// <summary>
///     创建人：  Riva
///     创建时间：2023/3/22 14:23:22
///     描述：依赖注入拓展类
/// </summary>
public static class ServiceCollectionExtensions
{
    /// <summary>
    ///     添加依赖注入接口
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddDependencyInjection(this IServiceCollection services)
    {
        // 添加内部依赖注入扫描拓展
        services.AddAutoInjection();
        return services;
    }

    /// <summary>
    ///     自住注入
    /// </summary>
    /// <param name="services"></param>
    private static void AddAutoInjection(this IServiceCollection services)
    {
        var baseTypes = new[]
            { typeof(IScopedDependency), typeof(ITransientDependency), typeof(ISingletonDependency) };

        // 获取所有能注册的接口
        var types = AppInfo.FindTypes(type => (baseTypes.Any(b => b.IsAssignableFrom(type))
                                               && type is
                                               {
                                                   IsClass: true, IsInterface: false, IsAbstract: false
                                               }
                                               && !type.HasAttribute<IgnoreDependencyAttribute>())
                                              || type.GetCustomAttribute<DependencyInjectionAttribute>() is not null);

        foreach (var implementedInterType in types)
        {
            //获取是否有特性注入
            var attr = implementedInterType.GetCustomAttribute<DependencyInjectionAttribute>();

            //获取类型
            var typeInfo = implementedInterType.GetTypeInfo();

            //获取服务类型
            var serviceTypes = typeInfo.ImplementedInterfaces
                .Where(x => x.HasMatchingGenericArity(typeInfo) && x != typeof(IDisposable))
                .Select(t => t.GetRegistrationType(typeInfo));

            //获取接口或特性类型
            var lifetime = GetServiceLifetime(implementedInterType);

            if (lifetime is null)
                break;

            var enumerable = serviceTypes as Type[] ?? serviceTypes.ToArray();
            if (!enumerable.Any())
            {
                services.Add(ServiceDescriptor.Describe(implementedInterType, implementedInterType,
                    lifetime.Value));
                continue;
            }

            if (attr?.AddSelf == true)
                services.Add(ServiceDescriptor.Describe(implementedInterType, implementedInterType,
                    lifetime.Value));

            foreach (var serviceType in enumerable)
                services.Add(ServiceDescriptor.Describe(serviceType, implementedInterType, lifetime.Value));
        }
    }

    /// <summary>
    ///     判断接口或特性类型
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private static ServiceLifetime? GetServiceLifetime(Type type)
    {
        var attr = type.GetCustomAttribute<DependencyInjectionAttribute>();
        return attr?.Lifetime ?? (typeof(IScopedDependency).IsAssignableFrom(type)
            ? ServiceLifetime.Scoped
            : typeof(ITransientDependency).IsAssignableFrom(type)
                ? ServiceLifetime.Transient
                : typeof(ISingletonDependency).IsAssignableFrom(type)
                    ? ServiceLifetime.Singleton
                    : null);
    }

    /// <summary>
    ///     获取IConfiguration
    /// </summary>
    /// <param name="services"></param>
    /// <returns></returns>
    public static IConfiguration GetConfiguration(this IServiceCollection services)
    {
        var hostBuilderContext = services.GetSingletonInstanceOrNull<HostBuilderContext>();
        var instance = hostBuilderContext?.Configuration as IConfigurationRoot;
        return instance ?? services.GetSingletonInstance<IConfiguration>();
    }

    /// <summary>
    ///     获取ServiceInfo
    /// </summary>
    /// <param name="services"></param>
    /// <returns></returns>
    public static IAppInfo GetServiceInfo(this IServiceCollection services)
    {
        return services.GetSingletonInstance<IAppInfo>();
    }

    /// <summary>
    ///     获取单列服务
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="services"></param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    public static T GetSingletonInstance<T>(this IServiceCollection services)
        where T : class
    {
        var instance = GetSingletonInstanceOrNull<T>(services);
        if (instance is null)
            throw new InvalidOperationException("Could not find singleton service: " + typeof(T).AssemblyQualifiedName);
        return instance;
    }

    /// <summary>
    ///     获取单列服务或null
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="services"></param>
    /// <returns></returns>
    internal static T? GetSingletonInstanceOrNull<T>(this IServiceCollection services)
        where T : class
    {
        var instance = services.FirstOrDefault(d => d.ServiceType == typeof(T))?.ImplementationInstance;
        if (instance is null)
            return null;

        return (T)instance;
    }
}